/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
 * MA  02110-1301, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package parser.serverData.skill;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;

import parser.clientData.clientSkills.SkillBaseClient;
import parser.clientData.clientStrings.ClientString;
import parser.util.DataManager;

/**
 * @author Mr. Poke
 *
 */
public class SkillSave
{
	public static void save()
	{
		ObjectFactory objFactory = new ObjectFactory();
		JAXBElement<SkillData> collection = objFactory.createSkillData(objFactory.createSkillData());
		List<SkillTemplate> templateList = collection.getValue().getSkillTemplate();

		for (SkillBaseClient clientSkill : DataManager.getInstance().getClientSkills())
		{
			SkillTemplate skill = new SkillTemplate();

			//startconditions
			Conditions startconditions = new Conditions();
			if (clientSkill.getCostDp() != 0)
			{
				DpCondition dpCondition = new DpCondition();
				dpCondition.setValue(clientSkill.getCostDp());
				startconditions.getMpAndHpAndDp().add(dpCondition);
			}

			if (clientSkill.getCostParameter() != null && clientSkill.getCostParameter().equalsIgnoreCase("hp") && clientSkill.getCostEnd() != 0)
			{
				HpCondition hpCondition = new HpCondition();
				hpCondition.setValue(clientSkill.getCostEnd());
				if (clientSkill.getCostEndLv() != 0)
					hpCondition.setDelta(clientSkill.getCostEndLv());
				startconditions.getMpAndHpAndDp().add(hpCondition);
			}

			if (clientSkill.getUseArrowCount() != 0)
			{
				ArrowCheckCondition arrowCheckCondition = new ArrowCheckCondition();
				startconditions.getMpAndHpAndDp().add(arrowCheckCondition);
			}

			if (clientSkill.getCostParameter() != null && clientSkill.getCostParameter().equalsIgnoreCase("MP") && clientSkill.getCostEnd() != 0)
			{
				MpCondition mpCondition = new MpCondition();
				mpCondition.setValue(clientSkill.getCostEnd());
				if (clientSkill.getCostEndLv() != 0)
					mpCondition.setDelta(clientSkill.getCostEndLv());
				startconditions.getMpAndHpAndDp().add(mpCondition);
			}

			if (clientSkill.getTargetSpeciesRestriction() != null && !clientSkill.getTargetSpeciesRestriction().equalsIgnoreCase("all"))
			{
				TargetCondition targetCondition = new TargetCondition();
				if (clientSkill.getTargetSpeciesRestriction().equalsIgnoreCase("NPC"))
					targetCondition.setValue(TargetAttribute.NPC);
				else if (clientSkill.getTargetSpeciesRestriction().equalsIgnoreCase("PC"))
					targetCondition.setValue(TargetAttribute.PC);
				else
					System.out.println("Missing target range TargetAttribute: " + clientSkill.getTargetSpeciesRestriction());

				startconditions.getMpAndHpAndDp().add(targetCondition);
			}
			if (!startconditions.getMpAndHpAndDp().isEmpty())
				skill.setStartconditions(startconditions);
			//setproperties
			TargetProperty target = new TargetProperty();
			boolean haveTarget = false;
			if (clientSkill.getTargetRelationRestriction() != null)
			{
				haveTarget = true;
				if (clientSkill.getTargetRelationRestriction().equalsIgnoreCase("Enemy"))
					target.setTargetRelation(TargetRelationAttribute.ENEMY);
				else if (clientSkill.getTargetRelationRestriction().equalsIgnoreCase("Friend"))
					target.setTargetRelation(TargetRelationAttribute.FRIEND);
				else if (clientSkill.getTargetRelationRestriction().equalsIgnoreCase("All"))
					target.setTargetRelation(TargetRelationAttribute.ALL);
				else if (clientSkill.getTargetRelationRestriction().equalsIgnoreCase("MyParty"))
					target.setTargetRelation(TargetRelationAttribute.MYPARTY);
				else
					System.out.println("Missing target range TargetRelationAttribute: " + clientSkill.getTargetRelationRestriction());
			}

			if (clientSkill.getFirstTarget() != null)
			{
				haveTarget = true;
				if (clientSkill.getFirstTarget().equalsIgnoreCase("Me"))
					target.setFirstTargetAttribute(FirstTargetAttribute.ME);
				else if (clientSkill.getFirstTarget().equalsIgnoreCase("Target"))
					target.setFirstTargetAttribute(FirstTargetAttribute.TARGET);
				else if (clientSkill.getFirstTarget().equalsIgnoreCase("Point"))
					target.setFirstTargetAttribute(FirstTargetAttribute.POINT);
				else if (clientSkill.getFirstTarget().equalsIgnoreCase("MyPet"))
					target.setFirstTargetAttribute(FirstTargetAttribute.MYPET);
				else if (clientSkill.getFirstTarget().equalsIgnoreCase("TargetorMe"))
					target.setFirstTargetAttribute(FirstTargetAttribute.TARGETORME);
				else if (clientSkill.getFirstTarget().equalsIgnoreCase("Target_MyParty_NonVisible"))
					target.setFirstTargetAttribute(FirstTargetAttribute.TARGET_MYPARTY_NONVISIBLE);
				else
					System.out.println("Missing target range FirstTargetAttribute: " + clientSkill.getFirstTarget());
			}

			if (clientSkill.getFirstTargetValidDistance() != 0)
			{
				haveTarget = true;
				target.setFirstTargetRange(clientSkill.getFirstTargetValidDistance());
			}

			if (clientSkill.getTargetRange() != null)
			{
				haveTarget = true;
				if (clientSkill.getTargetRange().equalsIgnoreCase("OnlyOne"))
					target.setTargetRange(TargetRangeAttribute.ONLYONE);
				else if (clientSkill.getTargetRange().equalsIgnoreCase("Area"))
					target.setTargetRange(TargetRangeAttribute.AREA);
				else if (clientSkill.getTargetRange().equalsIgnoreCase("Party"))
					target.setTargetRange(TargetRangeAttribute.PARTY);
				else if (clientSkill.getTargetRange().equalsIgnoreCase("Point"))
					target.setTargetRange(TargetRangeAttribute.POINT);
				else if (clientSkill.getTargetRange().equalsIgnoreCase("Party_WithPet"))
					target.setTargetRange(TargetRangeAttribute.PARTY_WITHPET);
				else
					System.out.println("Missing target range TargetRangeAttribute: " + clientSkill.getTargetRange());

			}
			if (clientSkill.getTargetRangeOpt1() != 0)
				target.setDistance(clientSkill.getTargetRangeOpt1());
			if (clientSkill.getTargetRangeOpt2() != 0)
				target.setRadius(clientSkill.getTargetRangeOpt2());
			if (clientSkill.getTargetRangeOpt3() != 0)
				target.setMaxcount(clientSkill.getTargetRangeOpt3());
			if (clientSkill.getAddWpnRange() != 0)
			{
				haveTarget = true;
				target.setAddWeaponRange(true);
			}

			if (haveTarget)
				skill.setTargetProperties(target);
			//useconditions

			Conditions useconditions = new Conditions();

			if (clientSkill.getMoveCasting() == 1)
			{
				skill.setAllowMove(true);
			}

			if (!useconditions.getMpAndHpAndDp().isEmpty())
				skill.setUseconditions(useconditions);

			//Actions

			Actions actions = new Actions();
			if (clientSkill.getCostDp() != 0)
			{
				DpUseAction dpUseAction = new DpUseAction();
				dpUseAction.setValue(clientSkill.getCostDp());
				actions.getItemuseAndMpuseAndHpuse().add(dpUseAction);
			}

			if (clientSkill.getDispelCategory() != null)
			{
				DispelInfo dispelInfo = new DispelInfo();
				try
				{
					if (clientSkill.getDispelCategory().equalsIgnoreCase("Npc_Buff"))
						dispelInfo.setCategory(DispelEffectId.BUFF);
					else if (clientSkill.getDispelCategory().equalsIgnoreCase("NPC_DebuffPhy"))
						dispelInfo.setCategory(DispelEffectId.DEBUFFPHY);
					else
						dispelInfo.setCategory(DispelEffectId.valueOf(clientSkill.getDispelCategory().toUpperCase()));
				}
				catch (Exception e)
				{
					System.out.println("Missing dispel category " + clientSkill.getDispelCategory());
				}
				dispelInfo.setLevel(clientSkill.getRequiredDispelLevel());
				if (dispelInfo.getCategory() != null)
					skill.setDispelInfo(dispelInfo);
			}
			if (clientSkill.getCostParameter() != null && clientSkill.getCostParameter().equalsIgnoreCase("hp") && clientSkill.getCostEnd() != 0)
			{
				HpUseAction hpUseAction = new HpUseAction();
				hpUseAction.setValue(clientSkill.getCostEnd());
				//if (clientSkill.getCostEndLv() != 0)
				//hpUseAction.setDelta(clientSkill.getCostEndLv());
				actions.getItemuseAndMpuseAndHpuse().add(hpUseAction);
			}

			if (clientSkill.getCostParameter() != null && clientSkill.getCostParameter().equalsIgnoreCase("MP") && clientSkill.getCostEnd() != 0)
			{
				MpUseAction mpUseAction = new MpUseAction();
				mpUseAction.setValue(clientSkill.getCostEnd());
				if (clientSkill.getCostEndLv() != 0)
					mpUseAction.setDelta(clientSkill.getCostEndLv());
				actions.getItemuseAndMpuseAndHpuse().add(mpUseAction);
			}

			if (clientSkill.getComponent() != null)
			{
				int itemId = DataManager.getInstance().getItemNameIdMap().get(clientSkill.getComponent().toLowerCase());
				if (itemId == 0)
				{
					System.out.println("Missing item: " + clientSkill.getComponent());
				}
				else
				{
					ItemUseAction itemUseAction = new ItemUseAction();
					itemUseAction.setItemid(itemId);
					itemUseAction.setCount(clientSkill.getComponentCount());
					actions.getItemuseAndMpuseAndHpuse().add(itemUseAction);
				}
			}

			if (!actions.getItemuseAndMpuseAndHpuse().isEmpty())
				skill.setActions(actions);

			skill.setSkillId(clientSkill.getId());
			ClientString name = DataManager.getInstance().getStringNameMap().get(clientSkill.getDesc().toLowerCase());
			skill.setName(name.getBody());
			skill.setNameId(name.getId() * 2 + 1);

			String stack = clientSkill.getDesc().substring(4);
			int lvlStringPos = stack.lastIndexOf("_G");
			if (lvlStringPos != -1)
			{
				try
				{
					skill.setLvl(Integer.valueOf(stack.substring(lvlStringPos + 2, lvlStringPos + 3 > stack.length() ? stack.length() : lvlStringPos + 3)));
					stack = stack.replace("_G" + skill.getLvl(), "");
				}
				catch (Exception e)
				{
					skill.setLvl(1);
				}
			}
			else
				skill.setLvl(1);
			skill.setStack(stack);

			if (clientSkill.getType() == null)
				skill.setSkilltype(SkillType.NONE);
			else if (clientSkill.getType().equalsIgnoreCase("Physical"))
				skill.setSkilltype(SkillType.PHYSICAL);
			else if (clientSkill.getType().equalsIgnoreCase("Magical"))
				skill.setSkilltype(SkillType.MAGICAL);
			else
				System.out.println("Missing SkillType: " + clientSkill.getType());

			if (clientSkill.getSubType() == null)
				skill.setSkillsubtype(SkillSubType.NONE);
			else if (clientSkill.getSubType().equalsIgnoreCase("Attack"))
				skill.setSkillsubtype(SkillSubType.ATTACK);
			else if (clientSkill.getSubType().equalsIgnoreCase("None"))
				skill.setSkillsubtype(SkillSubType.NONE);
			else if (clientSkill.getSubType().equalsIgnoreCase("Buff"))
				skill.setSkillsubtype(SkillSubType.BUFF);
			else if (clientSkill.getSubType().equalsIgnoreCase("Debuff"))
				skill.setSkillsubtype(SkillSubType.DEBUFF);
			else if (clientSkill.getSubType().equalsIgnoreCase("Heal"))
				skill.setSkillsubtype(SkillSubType.HEAL);
			else if (clientSkill.getSubType().equalsIgnoreCase("Summon"))
				skill.setSkillsubtype(SkillSubType.SUMMONTRAP);
			else if (clientSkill.getSubType().equalsIgnoreCase("Chant"))
				skill.setSkillsubtype(SkillSubType.CHANT);
			else if (clientSkill.getSubType().equalsIgnoreCase("SummonTrap"))
				skill.setSkillsubtype(SkillSubType.SUMMONTRAP);
			else if (clientSkill.getSubType().equalsIgnoreCase("SummonHoming"))
				skill.setSkillsubtype(SkillSubType.SUMMONHOMING);
			else
				System.out.println("Missing SkillSubType: " + clientSkill.getSubType());

			if (clientSkill.getTargetSlot() == null)
				skill.setTslot(TargetSlot.NONE);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("NoShow"))
				skill.setTslot(TargetSlot.NOSHOW);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("None"))
				skill.setTslot(TargetSlot.NONE);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("Buff"))
				skill.setTslot(TargetSlot.BUFF);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("Debuff"))
				skill.setTslot(TargetSlot.DEBUFF);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("Special"))
				skill.setTslot(TargetSlot.SPEC);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("Boost"))
				skill.setTslot(TargetSlot.BOOST);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("Chant"))
				skill.setTslot(TargetSlot.CHANT);
			else if (clientSkill.getTargetSlot().equalsIgnoreCase("special2"))
				skill.setTslot(TargetSlot.SPEC_2);
			else
				System.out.println("Missing TargetSlot: " + clientSkill.getTargetSlot());

			if (clientSkill.getActivationAttribute() == null)
				skill.setActivation(ActivationAttribute.NONE);
			else if (clientSkill.getActivationAttribute().equalsIgnoreCase("Active"))
				skill.setActivation(ActivationAttribute.ACTIVE);
			else if (clientSkill.getActivationAttribute().equalsIgnoreCase("Maintain"))
				skill.setActivation(ActivationAttribute.MAINTAIN);
			else if (clientSkill.getActivationAttribute().equalsIgnoreCase("Provoked"))
				skill.setActivation(ActivationAttribute.PROVOKED);
			else if (clientSkill.getActivationAttribute().equalsIgnoreCase("Passive"))
				skill.setActivation(ActivationAttribute.PASSIVE);
			else if (clientSkill.getActivationAttribute().equalsIgnoreCase("Toggle"))
				skill.setActivation(ActivationAttribute.TOGGLE);
			else
				System.out.println("Missing ActivationAttribute: " + clientSkill.getActivationAttribute());

			if (clientSkill.getCastingDelay() != 0)
				skill.setDuration(clientSkill.getCastingDelay());

			if (clientSkill.getDelayTime() != 0)
				skill.setCooldown(clientSkill.getDelayTime() / 100);

			if (clientSkill.getPvpDamageRatio() != 0)
				skill.setPvpDamage(clientSkill.getPvpDamageRatio());

			if (clientSkill.getPvpRemainTimeRatio() != 0)
				skill.setPvpDuration(clientSkill.getPvpRemainTimeRatio());

			if (clientSkill.getChainSkillProb2() != 0)
				skill.setChainSkillProb(clientSkill.getChainSkillProb2());

			if (clientSkill.getCancelRate() != 0)
				skill.setCancelRate(clientSkill.getCancelRate());

			switch (clientSkill.getId())
			{
				case 776:
				case 777:
				case 786:
					skill.setSkillsetException(3);
					//skill.setSkillsetMaxoccur(2);
					break;
				case 173:
				case 524:
					skill.setSkillsetException(7);
					break;
				case 969:
				case 970:
				case 971:
				case 989:
				case 2181:
				case 2183:
					skill.setSkillsetException(5);
					break;
				case 1105:
				case 1107:
				case 1108:
				case 1112:
				case 1186:
				case 1187: // TODO verify
					skill.setSkillsetException(4);
					break;
				case 1220:
				case 1221:
				case 1222:
				case 1267:
				case 1318:
				case 1319:
				case 1342:
					skill.setSkillsetException(5);
					break;
				case 1554:
				case 1555:
				case 1556:
				case 1587:
				case 1588:
					skill.setSkillsetException(8);
					break;
				case 1564:
				case 1565:
				case 1566:
				case 1574:
				case 1575: // TODO verify
				case 1576:
				case 1586:
				case 1590:
				case 1596:
				case 2210:
					skill.setSkillsetException(2);
					break;
				case 540:
				case 1636:
				case 1637:
				case 1685:
				case 1708:
				case 1781:
				case 1782:
				case 1935:
				case 2008:
				case 2062:
				case 2231:
				case 2232:
				case 8345:
					skill.setSkillsetException(6);
					break;
			}

			if (clientSkill.getChangeStance() != null)
				skill.setStance(true);

			//Effects

			Effects effects = new Effects();

			if (clientSkill.getCostChecktimeParameter() != null && clientSkill.getCostChecktimeParameter().equalsIgnoreCase("MP_Ratio"))
			{
				MpUseOverTimeEffect mpUseOverTimeEffect = new MpUseOverTimeEffect();
				mpUseOverTimeEffect.setValue(clientSkill.getCostToggle());
				mpUseOverTimeEffect.setChecktime(clientSkill.getCostChecktime());
				mpUseOverTimeEffect.setE(0);
				effects.getRootAndStunAndSleep().add(mpUseOverTimeEffect);
			}
			for (int index = 1; index <= 4; index++)
			{
				String type = getType(index, clientSkill);
				if (type == null)
					continue;
				if (type.equalsIgnoreCase("SpellATK_Instant"))
				{
					SpellAttackEffect spellAttackEffect = new SpellAttackEffect();
					spellAttackEffect.setE(index);
					setHop(index, clientSkill, spellAttackEffect);
					spellAttackEffect.setEffectid(getEffectId(index, clientSkill));
					String delta = (String) getReserved(index, 1, clientSkill);
					if (delta != null)
						spellAttackEffect.setDelta(Integer.valueOf(delta));
					spellAttackEffect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						spellAttackEffect.setElement(getElement(element));
					SubEffect sub = getSubEffect((String) getReserved(index, 14, clientSkill), index, clientSkill, spellAttackEffect);
					if (sub == null)
						spellAttackEffect.setModifiers(getModifier(index, clientSkill));
					effects.getRootAndStunAndSleep().add(spellAttackEffect);
				}
				else if (type.equalsIgnoreCase("CarveSignet"))
				{
					CarveSignetEffect effect = new CarveSignetEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String value = (String) getReserved(index, 4, clientSkill);
					if (value != null)
					{
						effect.setValue(Integer.valueOf((String) getReserved(index, 4, clientSkill)));
						effect.setDelta(Integer.valueOf((String) getReserved(index, 3, clientSkill)));
						int signetId = Integer.parseInt((String) getReserved(index, 13, clientSkill));
						if (signetId == 1)
						{
							effect.setSignetid(8303);
							effect.setSignet("SYSTEM_SKILL_SIGNET1");
						}
						else if (signetId == 2)
						{
							effect.setSignetid(8454);
							effect.setSignet("SYSTEM_SKILL_SIGNET2");
						}
						else if (signetId == 3)
						{
							effect.setSignetid(8507);
							effect.setSignet("SYSTEM_SKILL_SIGNET3");
						}
						else if (signetId == 4)
						{
							effect.setSignetid(8624);
							effect.setSignet("SYSTEM_SKILL_SIGNET4");
						}

						effect.setSignetlvl(Integer.parseInt((String) getReserved(index, 14, clientSkill)));
						effects.getRootAndStunAndSleep().add(effect);
					}
				}
				else if (type.equalsIgnoreCase("Signet"))
				{
					SignetEffect effect = new SignetEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					effect.setDuration(getRemain(index, clientSkill));
					setHop(index, clientSkill, effect);
					//TODO.....
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SignetBurst"))
				{
					SignetBurstEffect effect = new SignetBurstEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					int signetId = Integer.parseInt((String) getReserved(index, 7, clientSkill));
					if (signetId == 1)
					{
						effect.setSignet("SYSTEM_SKILL_SIGNET1");
					}
					else if (signetId == 2)
					{
						effect.setSignet("SYSTEM_SKILL_SIGNET2");
					}
					else if (signetId == 3)
					{
						effect.setSignet("SYSTEM_SKILL_SIGNET3");
					}
					else if (signetId == 4)
					{
						effect.setSignet("SYSTEM_SKILL_SIGNET4");
					}
					getSubEffect((String) getReserved(index, 13, clientSkill), index, clientSkill, effect);
					getSubEffect((String) getReserved(index, 15, clientSkill), index, clientSkill, effect);
					effect.setSignetlvl(Integer.parseInt((String) getReserved(index, 8, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("DashATK"))
				{
					DashEffect effect = new DashEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String value = (String) getReserved(index, 4, clientSkill);
					effect.setValue(Integer.valueOf(value));
					String delta = (String) getReserved(index, 3, clientSkill);
					if (delta != null)
						effect.setDelta(Integer.valueOf(delta));
					SubEffect sub = getSubEffect((String) getReserved(index, 14, clientSkill), index, clientSkill, effect);
					if (sub == null)
						effect.setModifiers(getModifier(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("DashATK"))
				{
					BackDashEffect effect = new BackDashEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String value = (String) getReserved(index, 4, clientSkill);
					effect.setValue(Integer.valueOf(value));
					String delta = (String) getReserved(index, 3, clientSkill);
					if (delta != null)
						effect.setDelta(Integer.valueOf(delta));
					SubEffect sub = getSubEffect((String) getReserved(index, 14, clientSkill), index, clientSkill, effect);
					if (sub == null)
						effect.setModifiers(getModifier(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SkillATK_Instant"))
				{
					SkillAttackEffect skillAttackEffect = new SkillAttackEffect();
					skillAttackEffect.setE(index);
					setHop(index, clientSkill, skillAttackEffect);
					String value = (String) getReserved(index, 4, clientSkill);
					if (value == null)
					{
						value = (String) getReserved(index, 2, clientSkill);
						skillAttackEffect.setMode(StatFunc.PERCENT);
					}
					else
						skillAttackEffect.setMode(StatFunc.ADD);
					skillAttackEffect.setValue(Integer.valueOf(value));
					String delta = (String) getReserved(index, 3, clientSkill);
					if (delta != null)
						skillAttackEffect.setDelta(Integer.valueOf(delta));

					String accMod = (String) getReserved(index, 5, clientSkill);
					if (accMod != null && !accMod.equalsIgnoreCase("0"))
						skillAttackEffect.setAccMod(Integer.valueOf(accMod));
					SubEffect sub = getSubEffect((String) getReserved(index, 14, clientSkill), index, clientSkill, skillAttackEffect);
					if (sub == null)
						skillAttackEffect.setModifiers(getModifier(index, clientSkill));
					effects.getRootAndStunAndSleep().add(skillAttackEffect);
				}
				else if (type.equalsIgnoreCase("ReturnHome"))
				{
					Effect effect = new ReturnEffect();
					effect.setE(index);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Heal_Instant"))
				{
					HealEffect heal = new HealEffect();
					heal.setE(index);
					setHop(index, clientSkill, heal);
					if (getReserved(index, 1, clientSkill) != null)
						heal.setDelta(Integer.parseInt((String) getReserved(index, 1, clientSkill)));
					heal.setValue(Integer.parseInt((String) getReserved(index, 2, clientSkill)));
					if (Integer.parseInt((String) getReserved(index, 6, clientSkill)) == 1)
						heal.setPercent(true);
					if (heal.getValue() < 0)
						System.out.println(skill.getSkillId()); //TODO Spirit Absorption I
					heal.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(heal);
				}
				else if (type.equalsIgnoreCase("MPHeal_Instant"))
				{
					HealMpEffect heal = new HealMpEffect();
					if (getReserved(index, 2, clientSkill) != null)
					{
						heal.setE(index);
						setHop(index, clientSkill, heal);
						if (getReserved(index, 1, clientSkill) != null)
							heal.setDelta(Integer.parseInt((String) getReserved(index, 1, clientSkill)));
						heal.setValue(Integer.parseInt((String) getReserved(index, 2, clientSkill)));
						if (heal.getValue() < 0)
							System.out.println(skill.getSkillId());
						if (Integer.parseInt((String) getReserved(index, 6, clientSkill)) == 1)
							heal.setPercent(true);
						heal.setEffectid(getEffectId(index, clientSkill));
						effects.getRootAndStunAndSleep().add(heal);
					}
				}
				else if (type.equalsIgnoreCase("DPHeal_Instant"))
				{
					HealDpEffect heal = new HealDpEffect();
					heal.setE(index);
					setHop(index, clientSkill, heal);
					if (getReserved(index, 1, clientSkill) != null)
						heal.setDelta(Integer.parseInt((String) getReserved(index, 1, clientSkill)));
					heal.setValue(Integer.parseInt((String) getReserved(index, 2, clientSkill)));
					if (Integer.parseInt((String) getReserved(index, 6, clientSkill)) == 1)
						heal.setPercent(true);
					heal.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(heal);
				}
				else if (type.equalsIgnoreCase("FPHeal_Instant"))
				{
					HealFpEffect heal = new HealFpEffect();
					heal.setE(index);
					setHop(index, clientSkill, heal);
					if (getReserved(index, 1, clientSkill) != null)
						heal.setDelta(Integer.parseInt((String) getReserved(index, 1, clientSkill)));
					heal.setValue(Integer.parseInt((String) getReserved(index, 2, clientSkill)));
					if (Integer.parseInt((String) getReserved(index, 6, clientSkill)) == 1)
						heal.setPercent(true);
					heal.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(heal);
				}
				else if (type.equalsIgnoreCase("Root"))
				{
					RootEffect effect = new RootEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Stun") || type.equalsIgnoreCase("BuffStun"))
				{
					StunEffect effect = new StunEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Sleep") || type.equalsIgnoreCase("BuffSleep"))
				{
					SleepEffect effect = new SleepEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Stumble"))
				{
					StumbleEffect effect = new StumbleEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Spin"))
				{
					SpinEffect effect = new SpinEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Bind") || type.equalsIgnoreCase("BuffBind"))
				{
					BindEffect effect = new BindEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Stagger"))
				{
					StaggerEffect effect = new StaggerEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("OpenAerial"))
				{
					OpenAerialEffect effect = new OpenAerialEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("CloseAerial"))
				{
					CloseAerialEffect effect = new CloseAerialEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Silence") || type.equalsIgnoreCase("BuffSilence"))
				{
					SilenceEffect effect = new SilenceEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Curse"))
				{
					CurseEffect effect = new CurseEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Snare"))
				{
					SnareEffect effect = new SnareEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					List<Change> changes = processStat(clientSkill.getId(), "Allspeed", getReserved(index, 1, clientSkill), getReserved(index, 2, clientSkill),
							getReserved(index, 6, clientSkill), true);
					effect.getChange().addAll(changes);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Slow"))
				{
					SlowEffect effect = new SlowEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					List<Change> changes = processStat(clientSkill.getId(), "attackdelay", getReserved(index, 1, clientSkill),
							getReserved(index, 2, clientSkill), getReserved(index, 6, clientSkill), true);
					effect.getChange().addAll(changes);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Shield"))
				{
					ShieldEffect effect = new ShieldEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setDelta(Integer.valueOf((String) getReserved(index, 7, clientSkill)));
					effect.setValue(Integer.valueOf((String) getReserved(index, 8, clientSkill)));
					effect.setHitdelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setHitvalue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					Object percent = getReserved(index, 6, clientSkill);
					if (percent != null && Integer.valueOf((String) percent) == 1)
						effect.setPercent(true);
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Statup"))
				{
					StatupEffect effect = new StatupEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					List<Change> changes = processStat(clientSkill.getId(), getReserved(index, 13, clientSkill), getReserved(index, 1, clientSkill),
							getReserved(index, 2, clientSkill), getReserved(index, 6, clientSkill), true);
					List<Change> changes2 = processStat(clientSkill.getId(), getReserved(index, 14, clientSkill), getReserved(index, 3, clientSkill),
							getReserved(index, 4, clientSkill), getReserved(index, 7, clientSkill), true);
					List<Change> changes3 = processStat(clientSkill.getId(), getReserved(index, 18, clientSkill), getReserved(index, 15, clientSkill),
							getReserved(index, 16, clientSkill), getReserved(index, 17, clientSkill), true);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.getChange().addAll(changes);
					effect.getChange().addAll(changes2);
					effect.getChange().addAll(changes3);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("StatBoost"))
				{
					StatboostEffect effect = new StatboostEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					Object add = getReserved(index, 2, clientSkill);
					Object percent = getReserved(index, 4, clientSkill);
					List<Change> changes = null;
					if (add == null || Integer.valueOf((String) add) == 0)
						changes = processStat(clientSkill.getId(), getReserved(index, 13, clientSkill), null, percent, "1", true);
					else
						changes = processStat(clientSkill.getId(), getReserved(index, 13, clientSkill), null, add, "0", true);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.getChange().addAll(changes);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("WeaponStatBoost"))
				{
					WeaponStatboostEffect effect = new WeaponStatboostEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					List<Change> changes = processStat(clientSkill.getId(), getReserved(index, 13, clientSkill), getReserved(index, 3, clientSkill),
							getReserved(index, 4, clientSkill), "1", true);
					effect.getChange().addAll(changes);
					effects.getRootAndStunAndSleep().add(effect);

				}
				else if (type.equalsIgnoreCase("Statdown"))
				{
					StatdownEffect effect = new StatdownEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					List<Change> changes = processStat(clientSkill.getId(), getReserved(index, 13, clientSkill), getReserved(index, 1, clientSkill),
							getReserved(index, 2, clientSkill), getReserved(index, 6, clientSkill), false);
					List<Change> changes2 = processStat(clientSkill.getId(), getReserved(index, 14, clientSkill), getReserved(index, 3, clientSkill),
							getReserved(index, 4, clientSkill), getReserved(index, 7, clientSkill), false);
					List<Change> changes3 = processStat(clientSkill.getId(), getReserved(index, 18, clientSkill), getReserved(index, 15, clientSkill),
							getReserved(index, 16, clientSkill), getReserved(index, 17, clientSkill), false);
					effect.getChange().addAll(changes);
					effect.getChange().addAll(changes2);
					effect.getChange().addAll(changes3);
					effects.getRootAndStunAndSleep().add(effect);

				}
				else if (type.equalsIgnoreCase("ProcHeal_Instant"))
				{
					ItemHealEffect effect = new ItemHealEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					Object percent = getReserved(index, 6, clientSkill);
					if (percent != null && ((String) percent).equalsIgnoreCase("1"))
						effect.setPercent(true);
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("ProcMpHeal_Instant"))
				{
					ItemHealMpEffect effect = new ItemHealMpEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					Object percent = getReserved(index, 6, clientSkill);
					if (percent != null && ((String) percent).equalsIgnoreCase("1"))
						effect.setPercent(true);
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("ProcDpHeal_Instant"))
				{
					ItemHealDpEffect effect = new ItemHealDpEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					Object percent = getReserved(index, 6, clientSkill);
					if (percent != null && ((String) percent).equalsIgnoreCase("1"))
						effect.setPercent(true);
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("ProcFpHeal_Instant"))
				{
					ItemHealFpEffect effect = new ItemHealFpEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					Object percent = getReserved(index, 6, clientSkill);
					if (percent != null && ((String) percent).equalsIgnoreCase("1"))
						effect.setPercent(true);
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SpellATK"))
				{
					DamageOverTimeEffect effect = new DamageOverTimeEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setDuration(getRemain(index, clientSkill));
					effect.setDelta(Integer.valueOf((String) getReserved(index, 8, clientSkill)));

					try
					{
						effect.setValue(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					}
					catch (Exception e)
					{
						effect.setValue(0);
					}
					effect.setChecktime(getChecktime(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Poison"))
				{
					PoisonEffect poison = new PoisonEffect();
					poison.setE(index);
					setHop(index, clientSkill, poison);
					poison.setEffectid(getEffectId(index, clientSkill));
					poison.setDuration(getRemain(index, clientSkill));
					poison.setChecktime(getChecktime(index, clientSkill));
					String value = (String) getReserved(index, 9, clientSkill);
					if (value != null)
						poison.setValue(Integer.valueOf(value));
					else
						poison.setValue(0);
					try
					{
						poison.setDelta(Integer.valueOf((String) getReserved(index, 8, clientSkill)));
					}
					catch (Exception e)
					{

					}
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						poison.setElement(getElement(element));
					effects.getRootAndStunAndSleep().add(poison);
				}
				else if (type.equalsIgnoreCase("Bleed"))
				{
					BleedEffect effect = new BleedEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setDuration(getRemain(index, clientSkill));
					effect.setDelta(Integer.valueOf((String) getReserved(index, 8, clientSkill)));

					try
					{
						effect.setValue(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					}
					catch (Exception e)
					{
						effect.setValue(0);
					}
					effect.setChecktime(getChecktime(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Heal") || type.equalsIgnoreCase("MPHeal") || type.equalsIgnoreCase("DPHeal") || type.equalsIgnoreCase("FPHeal")) // HOT
				{
					HealType hotType = HealType.HP;
					if (type.equalsIgnoreCase("MPHeal"))
						hotType = HealType.MP;
					else if (type.equalsIgnoreCase("DPHeal"))
						hotType = HealType.DP;
					else if (type.equalsIgnoreCase("FPHeal"))
						hotType = HealType.FP;
					HealOverTimeEffect effect = new HealOverTimeEffect();
					effect.setType(hotType);
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setDuration(getRemain(index, clientSkill));
					if (getReserved(index, 8, clientSkill) != null)
						effect.setDelta(Integer.valueOf((String) getReserved(index, 8, clientSkill)));
					Object percent = getReserved(index, 6, clientSkill);
					if (percent != null && ((String) percent).equalsIgnoreCase("1"))
						effect.setPercent(true);
					try
					{
						effect.setValue(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					}
					catch (Exception e)
					{
						effect.setValue(0);
					}
					effect.setChecktime(getChecktime(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Deform") || type.equalsIgnoreCase("ShapeChange"))
				{
					TransformEffect effect = new TransformEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					int npcId = DataManager.getInstance().getNpcNameIdMap().get(((String) getReserved(index, 9, clientSkill)).toLowerCase());
					if (npcId != 0)
					{
						effect.setModel(npcId);
						effects.getRootAndStunAndSleep().add(effect);
					}
					else
						System.out.println("Missing transform model ID: " + clientSkill.getId());
				}
				else if (type.equalsIgnoreCase("DelayedSpellATK_Instant"))
				{
					DelayDamageEffect effect = new DelayDamageEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setDelay(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Hide"))
				{
					HideEffect effect = new HideEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setValue(Integer.valueOf((String) getReserved(index, 7, clientSkill)));
					effect.setDuration(getRemain(index, clientSkill));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					if (getRemain(index, clientSkill) != null)
					{
						int percent = Integer.valueOf((String) getReserved(index, 2, clientSkill));
						percent = 100 - percent;
						if (percent > 0)
						{
							List<Change> changes = processStat(clientSkill.getId(), "speed", getReserved(index, 1, clientSkill), String.valueOf(percent), "1",
									false);
							effect.getChange().addAll(changes);
						}
					}
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Search"))
				{
					SearchEffect effect = new SearchEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setValue(Integer.valueOf((String) getReserved(index, 7, clientSkill)));
					effect.setDuration(getRemain(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Dispel"))
				{
					DispelEffect effect = new DispelEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					if (((String) getReserved(index, 1, clientSkill)).equalsIgnoreCase("Effect_Type"))
					{
						if (getReserved(index, 2, clientSkill) != null)
							effect.getEffectids().add(DispelEffectId.fromValue(((String) getReserved(index, 2, clientSkill)).toUpperCase()).ordinal());
						if (getReserved(index, 3, clientSkill) != null)
							effect.getEffectids().add(DispelEffectId.fromValue(((String) getReserved(index, 3, clientSkill)).toUpperCase()).ordinal());
						if (getReserved(index, 4, clientSkill) != null)
							effect.getEffectids().add(DispelEffectId.fromValue(((String) getReserved(index, 4, clientSkill)).toUpperCase()).ordinal());
						if (getReserved(index, 5, clientSkill) != null)
							effect.getEffectids().add(DispelEffectId.fromValue(((String) getReserved(index, 5, clientSkill)).toUpperCase()).ordinal());
						if (getReserved(index, 6, clientSkill) != null)
							effect.getEffectids().add(DispelEffectId.fromValue(((String) getReserved(index, 6, clientSkill)).toUpperCase()).ordinal());
						effect.setDispeltype(DispelType.EFFECTTYPE);
					}
					else if (((String) getReserved(index, 1, clientSkill)).equalsIgnoreCase("Effect_ID"))
					{
						if (getReserved(index, 2, clientSkill) != null)
							effect.getEffectids().add(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
						if (getReserved(index, 3, clientSkill) != null)
							effect.getEffectids().add(Integer.valueOf((String) getReserved(index, 3, clientSkill)));
						if (getReserved(index, 4, clientSkill) != null)
							effect.getEffectids().add(Integer.valueOf((String) getReserved(index, 4, clientSkill)));
						if (getReserved(index, 5, clientSkill) != null)
							effect.getEffectids().add(Integer.valueOf((String) getReserved(index, 5, clientSkill)));
						if (getReserved(index, 6, clientSkill) != null)
							effect.getEffectids().add(Integer.valueOf((String) getReserved(index, 6, clientSkill)));
						effect.setDispeltype(DispelType.EFFECTID);
					}
				}
				else if (type.equalsIgnoreCase("Wpn_Mastery"))
				{
					WeaponMasteryEffect weaponMasteryEffect = new WeaponMasteryEffect();
					weaponMasteryEffect.setE(index);
					weaponMasteryEffect.setEffectid(getEffectId(index, clientSkill));
					int basicLvl = getBasicLvl(index, clientSkill);
					if (basicLvl == 0)
						basicLvl = 1;
					weaponMasteryEffect.setBasiclvl(basicLvl);

					String weaponType = (String) getReserved(index, 5, clientSkill);
					weaponMasteryEffect.setWeapon(getWeaponType(weaponType));

					String value = (String) getReserved(index, 2, clientSkill);
					if (!value.equalsIgnoreCase("0"))
					{
						Change change = new Change();
						change.setStat(Modifiersenum.PHYSICAL_ATTACK);
						change.setFunc(StatFunc.PERCENT);
						change.setValue(value);
						weaponMasteryEffect.getChange().add(change);
					}
					effects.getRootAndStunAndSleep().add(weaponMasteryEffect);
				}
				else if (type.equalsIgnoreCase("Blind"))
				{
					BlindEffect effect = new BlindEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Disease"))
				{
					DeseaseEffect effect = new DeseaseEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("BoostHate"))
				{
					StatboostEffect effect = new StatboostEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					List<Change> changes = processStat(clientSkill.getId(), "speed", getReserved(index, 1, clientSkill),
							String.valueOf(getReserved(index, 2, clientSkill)), "1", true);
					effect.getChange().addAll(changes);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("HostileUp"))
				{
					HostileUpEffect effect = new HostileUpEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setValue(Integer.valueOf(((String) getReserved(index, 2, clientSkill)).trim()));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Paralyze"))
				{
					ParalyzeEffect effect = new ParalyzeEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					if (getReserved(index, 1, clientSkill) != null)
						effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Confuse"))
				{
					ConfuseEffect effect = new ConfuseEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setRandomtime(getRandomTime(index, 2, clientSkill));
					if (getReserved(index, 1, clientSkill) != null)
						effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("AlwaysDodge"))
				{
					AlwaysDodgeEffect alwaysDodgeEffect = new AlwaysDodgeEffect();
					alwaysDodgeEffect.setE(index);
					setHop(index, clientSkill, alwaysDodgeEffect);
					alwaysDodgeEffect.setEffectid(getEffectId(index, clientSkill));
					alwaysDodgeEffect.setDuration(getRemain(index, clientSkill));
					alwaysDodgeEffect.setValue(Integer.valueOf((String) getReserved(index, 13, clientSkill)));
					effects.getRootAndStunAndSleep().add(alwaysDodgeEffect);
				}
				else if (type.equalsIgnoreCase("AlwaysParry"))
				{
					AlwaysParryEffect alwaysParryEffect = new AlwaysParryEffect();
					alwaysParryEffect.setE(index);
					alwaysParryEffect.setEffectid(getEffectId(index, clientSkill));
					alwaysParryEffect.setDuration(getRemain(index, clientSkill));
					setHop(index, clientSkill, alwaysParryEffect);
					alwaysParryEffect.setValue(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					effects.getRootAndStunAndSleep().add(alwaysParryEffect);
				}
				else if (type.equalsIgnoreCase("AlwaysResist"))
				{
					AlwaysResistEffect effect = new AlwaysResistEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					effect.setDuration(getRemain(index, clientSkill));
					setHop(index, clientSkill, effect);
					effect.setValue(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("AlwaysBlock"))
				{
					AlwaysBlockEffect effect = new AlwaysBlockEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					effect.setDuration(getRemain(index, clientSkill));
					setHop(index, clientSkill, effect);
					effect.setValue(Integer.valueOf((String) getReserved(index, 9, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("DispelDebuffPhysical"))
				{
					DispelDebuffPhysicalEffect effect = new DispelDebuffPhysicalEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					if (getReserved(index, 1, clientSkill) != null)
						effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("DispelDebuff"))
				{
					DispelDebuffEffect effect = new DispelDebuffEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SwitchHPMP_Instant"))
				{
					Effect effect = new SwitchHpMpEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Aura"))
				{
					AuraEffect effect = new AuraEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effects.getRootAndStunAndSleep().add(effect);
					effect.setSkillId(DataManager.getInstance().getClientSkillsnameMap().get(((String) getReserved(index, 1, clientSkill)).toUpperCase())
							.getId());
					effect.setDistance(Integer.valueOf((String) getReserved(index, 3, clientSkill)));
				}
				else if (type.equalsIgnoreCase("Summon"))
				{
					SummonEffect effect = new SummonEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effect.setNpcId(DataManager.getInstance().getNpcNameIdMap().get(((String) getReserved(index, 1, clientSkill)).toUpperCase()));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Fear"))
				{
					FearEffect fearEffect = new FearEffect();
					setHop(index, clientSkill, fearEffect);
					fearEffect.setE(index);
					fearEffect.setEffectid(getEffectId(index, clientSkill));
					fearEffect.setDuration(getRemain(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						fearEffect.setElement(getElement(element));
					effects.getRootAndStunAndSleep().add(fearEffect);
				}
				else if (type.equalsIgnoreCase("dispeldebuffmental"))
				{
					DispelDebuffMentalEffect effect = new DispelDebuffMentalEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("reflector"))
				{
					ReflectorEffect effect = new ReflectorEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					if (getReserved(index, 2, clientSkill) != null)
						effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					else
						effect.setValue(0);
					if (getReserved(index, 1, clientSkill) != null)
						effect.setDelta(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					effect.setRadius(Integer.valueOf((String) getReserved(index, 5, clientSkill)));
					effect.setDuration(getRemain(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);

				}
				else if (type.equalsIgnoreCase("resurrect"))
				{
					Effect effect = new ResurrectEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("ResurrectPositional"))
				{
					//TODO
					Effect effect = new ResurrectEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("ReturnPoint"))
				{
					ReturnPointEffect effect = new ReturnPointEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Provoker"))
				{
					ProvokerEffect effect = new ProvokerEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					setHop(index, clientSkill, effect);
					effect.setSkillId(DataManager.getInstance().getClientSkillsnameMap().get(((String) getReserved(index, 17, clientSkill)).toUpperCase())
							.getId());
					effect.setDuration(getRemain(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					String provokeTarget = (String) getReserved(index, 14, clientSkill);
					if (provokeTarget.equalsIgnoreCase("Opponent"))
						effect.setProvokeTarget(ProvokeTarget.OPPONENT);
					else if (provokeTarget.equalsIgnoreCase("Me"))
						effect.setProvokeTarget(ProvokeTarget.ME);
					else
						System.out.println("UNKNOWN PROVOKER TARGET " + clientSkill.getId());
					String provokeType = (String) getReservedCond(index, 1, clientSkill);
					if (provokeType.equalsIgnoreCase("Nmlatk"))
						effect.setProvokeType(ProvokeType.ATTACK);
					else if (provokeType.equalsIgnoreCase("EveryHit"))
						effect.setProvokeType(ProvokeType.ATTACKED);
					else
						System.out.println("UNKNOWN PROVOKER TYPE " + clientSkill.getId());

					if (getReservedCondProb(index, 1, 1, clientSkill) != null)
						effect.setProb1((Integer) getReservedCondProb(index, 1, 1, clientSkill));
					if (getReservedCondProb(index, 1, 2, clientSkill) != null)
						effect.setProb2((Integer) getReservedCondProb(index, 1, 2, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SpellATKDrain_Instant"))
				{
					SpellAtkDrainInstantEffect effect = new SpellAtkDrainInstantEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					String value = (String) getReserved(index, 2, clientSkill);
					effect.setValue(Integer.valueOf(value));
					String delta = (String) getReserved(index, 1, clientSkill);
					if (delta != null)
						effect.setDelta(Integer.valueOf(delta));

					if (getReserved(index, 15, clientSkill) != null)
						effect.setHpPercent(Integer.valueOf((String) getReserved(index, 15, clientSkill)));
					if (getReserved(index, 17, clientSkill) != null)
						effect.setMpPercent(Integer.valueOf((String) getReserved(index, 17, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("OneTimeBoostSkillAttack"))
				{
					OneTimeBoostSkillAttackEffect oneTimeBoostSkillAttackEffect = new OneTimeBoostSkillAttackEffect();
					oneTimeBoostSkillAttackEffect.setE(index);
					oneTimeBoostSkillAttackEffect.setEffectid(getEffectId(index, clientSkill));
					oneTimeBoostSkillAttackEffect.setDuration(getRemain(index, clientSkill));
					oneTimeBoostSkillAttackEffect.setCount(Integer.valueOf((String) getReserved(index, 7, clientSkill)));
					setHop(index, clientSkill, oneTimeBoostSkillAttackEffect);
					Change change = new Change();
					String stat = (String) getReserved(index, 5, clientSkill);
					if (stat.equalsIgnoreCase("Magical"))
						change.setStat(Modifiersenum.MAGICAL_ATTACK);
					else
						change.setStat(Modifiersenum.PHYSICAL_ATTACK);
					change.setFunc(StatFunc.PERCENT);
					change.setValue((String) getReserved(index, 2, clientSkill));
					oneTimeBoostSkillAttackEffect.getChange().add(change);
					effects.getRootAndStunAndSleep().add(oneTimeBoostSkillAttackEffect);
				}
				else if (type.equalsIgnoreCase("Amr_Mastery"))
				{
					ArmorMasteryEffect effect = new ArmorMasteryEffect();
					effect.setE(index);
					effect.setEffectid(getEffectId(index, clientSkill));
					List<Change> changes = processStat(clientSkill.getId(), "physicaldefend", getReserved(index, 1, clientSkill),
							getReserved(index, 2, clientSkill), "1", true);
					effect.getChange().addAll(changes);
					effect.setArmor(getArmorType((String) getReserved(index, 5, clientSkill)));

					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("WeaponStatUp"))
				{
					List<Change> changes = processStat(clientSkill.getId(), getReserved(index, 13, clientSkill), getReserved(index, 1, clientSkill),
							getReserved(index, 2, clientSkill), getReserved(index, 6, clientSkill), true);
					WeaponStatupEffect effect = new WeaponStatupEffect();
					effect.getChange().addAll(changes);
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setWeapon((String) getReserved(index, 5, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effect.setDuration(getRemain(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("BoostSkillCastingTime"))
				{
					StatupEffect effect = new StatupEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					String txt = (String) getReserved(index, 3, clientSkill);
					if (txt.equalsIgnoreCase("none"))
						processChanges(effect.getChange(), StatFunc.PERCENT, -Integer.valueOf((String) getReserved(index, 2, clientSkill)),
								-Integer.valueOf((String) getReserved(index, 1, clientSkill)), Modifiersenum.BOOST_CASTING_TIME);
					else if (txt.equalsIgnoreCase("SummonTrap"))
						processChanges(effect.getChange(), StatFunc.PERCENT, -Integer.valueOf((String) getReserved(index, 2, clientSkill)),
								-Integer.valueOf((String) getReserved(index, 1, clientSkill)), Modifiersenum.BOOST_CASTING_TIME_TRAP);
					else if (txt.equalsIgnoreCase("heal"))
						processChanges(effect.getChange(), StatFunc.PERCENT, -Integer.valueOf((String) getReserved(index, 2, clientSkill)),
								-Integer.valueOf((String) getReserved(index, 1, clientSkill)), Modifiersenum.BOOST_CASTING_TIME_HEAL);
					else if (txt.equalsIgnoreCase("summon"))
						processChanges(effect.getChange(), StatFunc.PERCENT, -Integer.valueOf((String) getReserved(index, 2, clientSkill)),
								-Integer.valueOf((String) getReserved(index, 1, clientSkill)), Modifiersenum.BOOST_CASTING_TIME_SUMMON);
					else if (txt.equalsIgnoreCase("Summonhoming"))
						processChanges(effect.getChange(), StatFunc.PERCENT, Integer.valueOf((String) getReserved(index, 2, clientSkill)),
								Integer.valueOf((String) getReserved(index, 1, clientSkill)), Modifiersenum.BOOST_CASTING_TIME_SUMMONHOMING);
					else if (txt.equalsIgnoreCase("Attack"))
						processChanges(effect.getChange(), StatFunc.PERCENT, -Integer.valueOf((String) getReserved(index, 2, clientSkill)),
								-Integer.valueOf((String) getReserved(index, 1, clientSkill)), Modifiersenum.BOOST_CASTING_TIME_ATTACK);
					else
						System.out.println(txt);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SummonTrap"))
				{
					SummonTrapEffect effect = new SummonTrapEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String npcName = (String) getReserved(index, 9, clientSkill);
					int npcId = DataManager.getInstance().getNpcNameIdMap().get(npcName.toLowerCase());
					int skillId = 0;
					effect.setNpcId(npcId);
					switch (npcId)
					{
						case 749211:
						case 749212:
							skillId = 19093;
							break;
						
						default:
							String skillName = npcName.replaceAll("RA_", "").replaceAll("_NPC", "").replaceAll("EL_", "").replaceAll("Bab_", "");
							SkillBaseClient cSkill = DataManager.getInstance().getClientSkillsnameMap().get(skillName.toUpperCase());
							if (cSkill == null)
							{
								skillName = skillName.replaceAll("Light_", "").replaceAll("Dark_", "");
								cSkill = DataManager.getInstance().getClientSkillsnameMap().get(skillName.toUpperCase());
							}
							if (cSkill == null)
								System.out.println("Missing trap skill: " + npcId + " " + skill.getSkillId() + " " + skillName);
					}
					effect.setTime(Integer.valueOf((String) getReserved(index, 4, clientSkill)));
					effect.setSkillId(skillId);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SummonServant")
						|| type.equalsIgnoreCase("SummonTotem"))
				{
					SummonServantEffect effect = new SummonServantEffect();
					String npcName = (String) getReserved(index, 9, clientSkill);
					int npcId = DataManager.getInstance().getNpcNameIdMap().get(npcName.toLowerCase());
					effect.setNpcId(npcId);
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					int skillId = 0;
					switch (npcId)
					{
						case 749185:
							skillId = 18886;
							break;
						case 749186:
							skillId = 18887;
							break;
						case 749187:
							skillId = 19061;
							break;
						case 749188:
							skillId = 19061;
							break;
						case 749127:
						case 749129:
							skillId = 17815;
							break;
						case 749130:
						case 749128:
							skillId = 17816;
							break;
						default:
							String skillName = npcName.replaceAll("RA_", "").replaceAll("Light_", "")
							.replaceAll("Dark_", "").replaceAll("_NPC", "")
							.replaceAll("EL_", "").replaceAll("Bab_", "")
							.replaceAll("PR_", "").replaceAll("WI_", "");
							SkillBaseClient cSkill = DataManager.getInstance().getClientSkillsnameMap().get(skillName.toUpperCase());
							if (cSkill == null)
							{
								skillName = skillName.replaceAll("Light_", "").replaceAll("Dark_", "");
								cSkill = DataManager.getInstance().getClientSkillsnameMap().get(skillName.toUpperCase());
							}
							if (cSkill == null)
								System.out.println("Missing servant skill: " + npcId + " " + skill.getSkillId() + " " + skillName);
					}
					effect.setHpRatio(Integer.valueOf((String) getReserved(index, 4, clientSkill)));
					effect.setSkillId(skillId);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SkillATKDrain_Instant"))
				{
					SkillAtkDrainInstantEffect effect = new SkillAtkDrainInstantEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					String value = (String) getReserved(index, 4, clientSkill);
					if (value == null)
					{
						value = (String) getReserved(index, 2, clientSkill);
						effect.setMode(StatFunc.PERCENT);
					}
					else
						effect.setMode(StatFunc.ADD);
					effect.setValue(Integer.valueOf(value));
					String delta = (String) getReserved(index, 3, clientSkill);
					if (delta != null)
						effect.setDelta(Integer.valueOf(delta));
					Object hp = (String) getReserved(index, 15, clientSkill);
					if (hp!= null && Integer.valueOf((String)hp) > 0)
					{
						effect.setPercent(Integer.parseInt((String)hp));
						effect.setHealType(HealType.HP);
					}
					Object mp = (String) getReserved(index, 17, clientSkill);
					if (mp!= null && Integer.valueOf((String)mp) > 0)
					{
						effect.setPercent(Integer.parseInt((String)mp));
						effect.setHealType(HealType.MP);
					}
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("PetOrderUseUltraSkill"))
				{
					PetOrderUseUltraSkillEffect petOrderUseUltraSkillEffect = new PetOrderUseUltraSkillEffect();
					petOrderUseUltraSkillEffect.setE(index);
					petOrderUseUltraSkillEffect.setUltraSkill(Integer.valueOf((String) getReserved(index, 1, clientSkill)));
					setHop(index, clientSkill, petOrderUseUltraSkillEffect);
					effects.getRootAndStunAndSleep().add(petOrderUseUltraSkillEffect);
				}
				else if (type.equalsIgnoreCase("BoostHealEffect"))
				{
					StatupEffect effect = new StatupEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					List<Change> changes = processStat(clientSkill.getId(), "HealSkillBoost", null,
							getReserved(index, 2, clientSkill), "1", true);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.getChange().addAll(changes);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("DispelBuff"))
				{
					DispelBuffEffect effect = new DispelBuffEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setCount(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SkillLauncher"))
				{
					SkillLauncherEffect effect = new SkillLauncherEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setValue(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					String skillName = (String) getReserved(index, 1, clientSkill);
					SkillBaseClient cSkill = DataManager.getInstance().getClientSkillsnameMap().get(skillName.toUpperCase());
					effect.setSkillId(cSkill.getId());
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Pulled"))
				{
					PulledEffect effect = new PulledEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setDuration(getRemain(index, clientSkill));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("MoveBehindATK"))
				{
					MoveBehindEffect effect = new MoveBehindEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setValue(Integer.valueOf((String) getReserved(index, 4, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("Rebirth")) 
				{
					RebirthEffect effect = new RebirthEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					effect.setDuration(getRemain(index, clientSkill));
					if (getReserved(index, 2, clientSkill) == null)
						effect.setResurrectPercent(25);
					else
						effect.setResurrectPercent(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("BoostSkillCost"))
				{
					StatupEffect effect = new StatupEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					List<Change> changes = processStat(clientSkill.getId(), "BoostSkillCost", null,
							getReserved(index, 2, clientSkill), "1", true);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.getChange().addAll(changes);
					effects.getRootAndStunAndSleep().add(effect);
				
				}
				else if (type.equalsIgnoreCase("DeboostHealAmount"))
				{
					StatupEffect effect = new StatupEffect();
					effect.setE(index);
					setHop(index, clientSkill, effect);
					effect.setDuration(getRemain(index, clientSkill));
					effect.setEffectid(getEffectId(index, clientSkill));
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						effect.setElement(getElement(element));
					Object add = getReserved(index, 1, clientSkill);
					String value = (String)getReserved(index, 2, clientSkill);
					boolean percent = true;
					if (add != null && (Integer.valueOf((String)add) > 0))
					{
						value = (String)add;
						percent = false;
					}
					List<Change> changes = processStat(clientSkill.getId(), "HealSkillBoost", null,
							value, percent?"1":"0", false);
					Object fly = getReserved(index, 9, clientSkill);
					if (fly != null && ((String) fly).equalsIgnoreCase("1"))
						skill.setOnFly(true);
					effect.getChange().addAll(changes);
					effects.getRootAndStunAndSleep().add(effect);
				}
				else if (type.equalsIgnoreCase("SummonGroupGate"))
				{
					SummonGroupGateEffect summonGroupGateEffect = new SummonGroupGateEffect();
					summonGroupGateEffect.setE(index);
					summonGroupGateEffect.setTime(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					String npcName = (String) getReserved(index, 9, clientSkill);
					int npcId = DataManager.getInstance().getNpcNameIdMap().get(npcName.toLowerCase());
					summonGroupGateEffect.setNpcId(npcId);
					effects.getRootAndStunAndSleep().add(summonGroupGateEffect);
				}
				else if (type.equalsIgnoreCase("MagicCounterATK"))
				{
					MagicCounterAtkEffect magicCounterAtkEffect = new MagicCounterAtkEffect();
					magicCounterAtkEffect.setE(index);
					String element = (String) getReserved(index, 10, clientSkill);
					if (element != null)
						magicCounterAtkEffect.setElement(getElement(element));
					setHop(index, clientSkill, magicCounterAtkEffect);
					magicCounterAtkEffect.setEffectid(getEffectId(index, clientSkill));
					magicCounterAtkEffect.setDuration(getRemain(index, clientSkill));
					magicCounterAtkEffect.setPercent(Integer.valueOf((String) getReserved(index, 2, clientSkill)));
					magicCounterAtkEffect.setMaxdmg(Integer.valueOf((String) getReserved(index, 5, clientSkill)));
					effects.getRootAndStunAndSleep().add(magicCounterAtkEffect);
				}
				else
					System.out.println("Missing type: "+type);
			}

			if (!effects.getRootAndStunAndSleep().isEmpty())
			{
				skill.setEffects(effects);
			}

			templateList.add(skill);
		}
		try
		{
			JAXBContext jaxbContext = JAXBContext.newInstance("parser.serverData.skill");
			Marshaller marshaller = jaxbContext.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
			marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "skill_templates.xsd");
			marshaller.marshal(collection, new FileOutputStream("static_data/skill/skill_templates.xml"));
		}
		catch (PropertyException e)
		{
			e.printStackTrace();
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (JAXBException e)
		{
			e.printStackTrace();
		}
	}

	private static String getType(int index, SkillBaseClient clientSkill)
	{
		try
		{
			return (String) clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Type").invoke(clientSkill, new Object[] {});
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	private static Integer getEffectId(int index, SkillBaseClient clientSkill)
	{
		try
		{
			Object id = clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Effectid").invoke(clientSkill, new Object[] {});
			if (id != null)
				return (Integer) id;
			else
				return null;
		}
		catch (Exception e)
		{
			System.out.println(clientSkill.getId());
			//e.printStackTrace();
			return null;
		}
	}

	private static int getBasicLvl(int index, SkillBaseClient clientSkill)
	{
		try
		{
			return (Integer) clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Basiclv").invoke(clientSkill, new Object[] {});
		}
		catch (Exception e)
		{
			return 0;
		}
	}

	private static Object getReserved(int index, int id, SkillBaseClient clientSkill)
	{
		try
		{
			return clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Reserved" + id).invoke(clientSkill, new Object[] {});
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	private static Object getReservedCond(int index, int id, SkillBaseClient clientSkill)
	{
		try
		{
			return clientSkill.getClass().getDeclaredMethod("getEffect" + index + "ReservedCond" + id).invoke(clientSkill, new Object[] {});
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	private static Object getReservedCondProb(int index, int id, int num, SkillBaseClient clientSkill)
	{
		try
		{
			return clientSkill.getClass().getDeclaredMethod("getEffect" + index + "ReservedCond" + id + "Prob" + num).invoke(clientSkill, new Object[] {});
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	private static Integer getRemain(int index, SkillBaseClient clientSkill)
	{
		try
		{
			int result = 0;
			Object value = clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Remain" + 1).invoke(clientSkill, new Object[] {});
			if (value != null)
				result = (Integer) value;
			Object value2 = clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Remain" + 2).invoke(clientSkill, new Object[] {});
			if (value2 != null)
				result += (Integer) value2;
			if (result > 0)
				return result;
			return null;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return 0;
		}
	}

	private static Integer getRandomTime(int index, int id, SkillBaseClient clientSkill)
	{
		try
		{
			Object value = clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Randomtime").invoke(clientSkill, new Object[] {});
			if (value != null)
				return (Integer) value;
			return null;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	private static int getChecktime(int index, SkillBaseClient clientSkill)
	{
		try
		{
			return (Integer) clientSkill.getClass().getDeclaredMethod("getEffect" + index + "Checktime").invoke(clientSkill, new Object[] {});
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return 0;
		}
	}

	private static WeaponType getWeaponType(String text)
	{
		if (text.equalsIgnoreCase("1h_dagger"))
			return WeaponType.DAGGER_1_H;
		if (text.equalsIgnoreCase("1h_mace"))
			return WeaponType.MACE_1_H;
		if (text.equalsIgnoreCase("1h_sword"))
			return WeaponType.SWORD_1_H;
		if (text.equalsIgnoreCase("1h_toolhoe"))
			return WeaponType.TOOLHOE_1_H;
		if (text.equalsIgnoreCase("2h_toolrod"))
			return WeaponType.TOOLROD_2_H;
		if (text.equalsIgnoreCase("2h_book"))
			return WeaponType.BOOK_2_H;
		if (text.equalsIgnoreCase("2h_orb"))
			return WeaponType.ORB_2_H;
		if (text.equalsIgnoreCase("2h_polearm"))
			return WeaponType.POLEARM_2_H;
		if (text.equalsIgnoreCase("2h_staff"))
			return WeaponType.STAFF_2_H;
		if (text.equalsIgnoreCase("2h_sword"))
			return WeaponType.SWORD_2_H;
		if (text.equalsIgnoreCase("2h_toolpick"))
			return WeaponType.TOOLPICK_2_H;
		if (text.equalsIgnoreCase("2h_toolrod"))
			return WeaponType.TOOLROD_2_H;
		if (text.equalsIgnoreCase("bow"))
			return WeaponType.BOW;
		System.out.println(text);
		return null;
	}

	private static ArmorType getArmorType(String text)
	{
		if (text.equalsIgnoreCase("clothes"))
			return ArmorType.CLOTHES;
		if (text.equalsIgnoreCase("chain"))
			return ArmorType.CHAIN;
		if (text.equalsIgnoreCase("robe"))
			return ArmorType.ROBE;
		if (text.equalsIgnoreCase("leather"))
			return ArmorType.LEATHER;
		if (text.equalsIgnoreCase("plate"))
			return ArmorType.PLATE;
		System.out.println(text);
		return null;
	}

	private static void setHop(int index, SkillBaseClient clientSkill, Effect effect)
	{
		try
		{
			String hopType = (String) clientSkill.getClass().getDeclaredMethod("getEffect" + index + "HopType").invoke(clientSkill, new Object[] {});

			Object hopA = clientSkill.getClass().getDeclaredMethod("getEffect" + index + "HopA").invoke(clientSkill, new Object[] {});
			Object hopB = (Integer) clientSkill.getClass().getDeclaredMethod("getEffect" + index + "HopB").invoke(clientSkill, new Object[] {});

			if (hopType == null)
				return;

			effect.setHoptype(HopType.valueOf(hopType.toUpperCase()));
			if (hopA != null)
				effect.setHopa((Integer) hopA);
			if (hopB != null)
				effect.setHopb((Integer) hopB);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private static SkillElement getElement(String text)
	{
		if (text.equalsIgnoreCase("Earth"))
			return SkillElement.EARTH;
		else if (text.equalsIgnoreCase("Air"))
			return SkillElement.WIND;
		else if (text.equalsIgnoreCase("Water"))
			return SkillElement.WATER;
		else if (text.equalsIgnoreCase("Fire"))
			return SkillElement.FIRE;
		else if (text.equalsIgnoreCase("light"))
			return SkillElement.LIGHT;
		else if (text.equalsIgnoreCase("Dark"))
			return SkillElement.DARK;
		System.out.println("Missing SkillElement: " + text);
		return null;
	}

	private static SubEffect getSubEffect(String name, int index, SkillBaseClient clientSkill, Effect effect)
	{
		if (name == null)
			return null;
		SubEffect sub = new SubEffect();
		if ("OpenAerial".equalsIgnoreCase(name))
		{
			effect.setSubeffect(sub);
			effect.getSubeffect().setSkillId(8224);
			return sub;
		}
		else if (name.contains("Stumble") || name.contains("stumble"))
		{
			effect.setSubeffect(sub);
			effect.getSubeffect().setSkillId(8218);
			return sub;
		}
		else if (name.contains("Spin") || name.contains("spin"))
		{
			effect.setSubeffect(sub);
			effect.getSubeffect().setSkillId(8223);
			return sub;
		}
		else if (name.contains("Stagger") || name.contains("stagger"))
		{
			effect.setSubeffect(sub);
			effect.getSubeffect().setSkillId(8217);
			return sub;
		}
		else if (name.contains("Pulled"))
		{
			effect.setSubeffect(sub);
			effect.getSubeffect().setSkillId(8441);
			return sub;
		}
		else
		{
			SkillBaseClient skill = DataManager.getInstance().getClientSkillsnameMap().get(name.toUpperCase());
			if (skill != null)
			{
				effect.setSubeffect(sub);
				effect.getSubeffect().setSkillId(skill.getId());
				return sub;
			}
			else
				System.out.println("Missing sub effect:" + name);
		}
		return null;
	}

	private static ActionModifiers getModifier(int index, SkillBaseClient clientSkill)
	{
		String modifierName = (String) getReserved(index, 16, clientSkill);

		if (modifierName == null)
			return null;

		ActionModifiers modifiers = new ActionModifiers();
		Object value = getReserved(index, 10, clientSkill);
		if (modifierName.contains("_Back") && value != null)
		{
			AngleDamageModifier bdModifier = new AngleDamageModifier();
			bdModifier.setIsBack(true);
			bdModifier.setValue(Integer.parseInt((String) value));
			bdModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(bdModifier);
		}

		if (modifierName.contains("_Front") && value != null)
		{
			AngleDamageModifier frontModifier = new AngleDamageModifier();
			frontModifier.setIsBack(false);
			frontModifier.setValue(Integer.parseInt((String) value));
			frontModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(frontModifier);
		}

		if (modifierName.contains("Stun") && value != null)
		{
			EffectDamageModifier stunModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				stunModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				try
				{
					stunModifier.setValue(Integer.parseInt((String) value));
					stunModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
				}
				catch (Exception e)
				{
					stunModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
					stunModifier.setDelta(Integer.parseInt((String) getReserved(index, 8, clientSkill)));
				}
			}
			stunModifier.setEffectId(EffectId.STUN);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(stunModifier);
		}
		if (modifierName.contains("Stumble") && value != null)
		{
			EffectDamageModifier stumbleModifier = new EffectDamageModifier();
			stumbleModifier.setValue(Integer.parseInt((String) value));
			stumbleModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			stumbleModifier.setEffectId(EffectId.STUMBLE);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(stumbleModifier);
		}
		if (modifierName.contains("Bleed") && value != null)
		{
			EffectDamageModifier stumbleModifier = new EffectDamageModifier();
			stumbleModifier.setValue(Integer.parseInt((String) value));
			stumbleModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			stumbleModifier.setEffectId(EffectId.BLEED);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(stumbleModifier);
		}
		if (modifierName.contains("Paralyze") && value != null)
		{
			EffectDamageModifier stumbleModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				stumbleModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				stumbleModifier.setValue(Integer.parseInt((String) value));
				stumbleModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			stumbleModifier.setEffectId(EffectId.PARALYZE);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(stumbleModifier);
		}
		if (modifierName.contains("snare") && value != null)
		{
			EffectDamageModifier stumbleModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				stumbleModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				stumbleModifier.setValue(Integer.parseInt((String) value));
				stumbleModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			stumbleModifier.setEffectId(EffectId.SNARE);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(stumbleModifier);
		}
		if (modifierName.contains("Deform") && value != null)
		{
			/*
			EffectDamageModifier stumbleModifier = new EffectDamageModifier();
			stumbleModifier.setValue(Integer.parseInt((String) value));
			stumbleModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			stumbleModifier.setEffect(EffectId.);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(stumbleModifier);
			*/
			//TODO Transformed....
		}
		if (modifierName.contains("Poison") && value != null)
		{
			EffectDamageModifier poisonModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				poisonModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				poisonModifier.setValue(Integer.parseInt((String) value));
				poisonModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			poisonModifier.setEffectId(EffectId.POISON);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(poisonModifier);
		}
		if (modifierName.contains("Curse") && value != null)
		{
			EffectDamageModifier poisonModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				poisonModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				poisonModifier.setValue(Integer.parseInt((String) value));
				poisonModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			poisonModifier.setEffectId(EffectId.CURSE);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(poisonModifier);
		}
		if (modifierName.contains("OpenAerial") && value != null)
		{
			EffectDamageModifier poisonModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				poisonModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				poisonModifier.setValue(Integer.parseInt((String) value));
				poisonModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			poisonModifier.setEffectId(EffectId.OPENAERIAL);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(poisonModifier);
		}
		if (modifierName.contains("Fear") && value != null)
		{
			EffectDamageModifier poisonModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				poisonModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				poisonModifier.setValue(Integer.parseInt((String) value));
				poisonModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			poisonModifier.setEffectId(EffectId.FEAR);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(poisonModifier);
		}
		if (modifierName.contains("Blind") && value != null)
		{
			EffectDamageModifier poisonModifier = new EffectDamageModifier();
			String unk = (String) getReserved(index, 4, clientSkill);
			if (unk != null && unk.equalsIgnoreCase("BasicDMG"))
				poisonModifier.setValue(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			else
			{
				poisonModifier.setValue(Integer.parseInt((String) value));
				poisonModifier.setDelta(Integer.parseInt((String) getReserved(index, 9, clientSkill)));
			}
			poisonModifier.setEffectId(EffectId.BLIND);
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(poisonModifier);
		}
		String[] parts = modifierName.split(",");

		TargetRaceDamageModifier mod = new TargetRaceDamageModifier();
		for (String part : parts)
		{
			part = part.trim();
			if (part.equalsIgnoreCase("Poison") || part.equalsIgnoreCase("Stumble") || part.equalsIgnoreCase("_Front") || part.equalsIgnoreCase("Stun")
					|| part.equalsIgnoreCase("_Back") || part.equalsIgnoreCase("Deform") || part.equalsIgnoreCase("snare") || part.equalsIgnoreCase("Bleed")
					|| part.equalsIgnoreCase("Paralyze") || part.equalsIgnoreCase("OpenAerial") || part.equalsIgnoreCase("Curse")
					|| part.equalsIgnoreCase("Fear") || part.equalsIgnoreCase("Blind"))
				continue;
			try
			{
				if (value != null)
				{
					int valueInt = 0;
					int delta = 0;

					if ((String) getReserved(index, 8, clientSkill) != null)
					{
						valueInt = Integer.parseInt((String) getReserved(index, 9, clientSkill));
						delta = Integer.parseInt((String) getReserved(index, 8, clientSkill));
					}
					else
					{
						valueInt = Integer.parseInt((String) getReserved(index, 10, clientSkill));
						delta = Integer.parseInt((String) getReserved(index, 9, clientSkill));
					}
					mod.setValue(valueInt);
					mod.setDelta(delta);

					if (part.equalsIgnoreCase("_Race_PC_Dark"))
					{
						mod.getRaces().add(Race.ASMODIANS);
					}
					else if (part.equalsIgnoreCase("_Race_PC_Light"))
					{
						mod.getRaces().add(Race.ELYOS);
					}
					else if (part.equalsIgnoreCase("_Race_Drakan"))
					{
						mod.getRaces().add(Race.DRAKAN);
					}
					else if (part.equalsIgnoreCase("_Race_PC_Light_Castle_door"))
					{
						mod.getRaces().add(Race.PC_LIGHT_CASTLE_DOOR);
					}
					else if (part.equalsIgnoreCase("_Race_PC_Dark_Castle_door"))
					{
						mod.getRaces().add(Race.PC_DARK_CASTLE_DOOR);
					}
					else if (part.equalsIgnoreCase("_Race_Dragon_Castle_Door"))
					{
						mod.getRaces().add(Race.DRAGON_CASTLE_DOOR);
					}
					else if (part.equalsIgnoreCase("_Race_lizardman"))
					{
						mod.getRaces().add(Race.LIZARDMAN);
					}
					else if (part.equalsIgnoreCase("_Race_naga"))
					{
						mod.getRaces().add(Race.NAGA);
					}
					else if (part.equalsIgnoreCase("_Race_Elemental"))
					{
						mod.getRaces().add(Race.ELEMENTAL);
					}
					else if (part.equalsIgnoreCase("_Race_GChief_Light"))
					{
						mod.getRaces().add(Race.GCHIEF_LIGHT);
					}
					else if (part.equalsIgnoreCase("_Race_GChief_Dark"))
					{
						mod.getRaces().add(Race.GCHIEF_DARK);
					}
					else if (part.equalsIgnoreCase("_Race_Carrier"))
					{
						mod.getRaces().add(Race.CARRIER);
					}
					else if (part.equalsIgnoreCase("_Race_Outsider"))
					{
						mod.getRaces().add(Race.OUTSIDER);
					}
					else
						System.out.println("Missing race: " + part);
				}

			}
			catch (Exception ex)
			{
				System.out.println("Exception in skill during race modifier parse. skillId: " + clientSkill.getId());
				//ex.printStackTrace();
			}
		}
		if (!mod.getRaces().isEmpty())
		{
			modifiers.getAngledamageAndEffectdamageAndTargetrace().add(mod);
		}
		if (modifiers.getAngledamageAndEffectdamageAndTargetrace().isEmpty())
			return null;
		else
			return modifiers;
	}

	private static StatFunc getFuncFor(Object object)
	{
		if (object == null)
			return StatFunc.ADD;
		String reservedString = (String) object;
		if (reservedString.equals("1"))
			return StatFunc.PERCENT;
		else if (reservedString.equals("0"))
			return StatFunc.ADD;
		System.out.println("UNKNOWN FUNC reserved string:" + reservedString);
		return null;
	}

	private static List<Change> processStat(int skillId, Object statString, Object delta, Object value, Object function, boolean isUp)
	{
		List<Change> changes = new ArrayList<Change>();

		if (statString == null)
			return changes;
		if (delta == null)
			delta = "0";
		String stat = (String) statString;
		if (stat.equalsIgnoreCase("PMAttack"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PHYSICAL_ATTACK,
					Modifiersenum.MAGICAL_ATTACK);
			return changes;
		}
		else if (stat.equalsIgnoreCase("PMDefend"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PHYSICAL_DEFENSE,
					Modifiersenum.EARTH_RESISTANCE, Modifiersenum.WATER_RESISTANCE, Modifiersenum.WIND_RESISTANCE, Modifiersenum.FIRE_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("phyattack"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PHYSICAL_ATTACK);
			return changes;
		}
		else if (stat.equalsIgnoreCase("PhysicalDefend"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PHYSICAL_DEFENSE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ActiveDefend"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.EVASION,
					Modifiersenum.PARRY, Modifiersenum.BLOCK);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MaxHP"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.MAXHP);
			return changes;
		}
		else if (stat.equalsIgnoreCase("maxmp"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.MAXMP);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MaxFp"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.FLY_TIME);
			return changes;
		}
		else if (stat.equalsIgnoreCase("HPRegen"))
		{
			processChanges(changes, getFuncFor(function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.REGEN_HP);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MPRegen"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.REGEN_MP);
			return changes;
		}
		else if (stat.equalsIgnoreCase("FPRegen"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.REGEN_FP);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Block"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.BLOCK);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Parry"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PARRY);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Dodge"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.EVASION);
			return changes;
		}
		else if (stat.equalsIgnoreCase("critical"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PHYSICAL_CRITICAL);
			return changes;
		}
		else if (stat.equalsIgnoreCase("hitAccuracy"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PHYSICAL_ACCURACY);
			return changes;
		}
		else if (stat.equalsIgnoreCase("attackdelay"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? -1 : 1), Integer.parseInt((String) delta) * (isUp ? -1 : 1), Modifiersenum.ATTACK_SPEED);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ElementalDefendAll") || stat.equalsIgnoreCase("magicalDefend"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.EARTH_RESISTANCE,
					Modifiersenum.WATER_RESISTANCE, Modifiersenum.WIND_RESISTANCE, Modifiersenum.FIRE_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ElementalDefendWater") || stat.equalsIgnoreCase("erWater"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.WATER_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ElementalDefendAir") || stat.equalsIgnoreCase("erair"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.WIND_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ElementalDefendDark"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.ELEMENTAL_RESISTANCE_DARK);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ElementalDefendLight"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.ELEMENTAL_RESISTANCE_LIGHT);
			return changes;
		}
		else if (stat.equalsIgnoreCase("erearth") || stat.equalsIgnoreCase("ElementalDefendEarth"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.EARTH_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("erfire") || stat.equalsIgnoreCase("ElementalDefendFire"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.FIRE_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MagicalSkillBoost"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.BOOST_MAGICAL_SKILL);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MagicalResist"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.MAGICAL_RESIST);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MagicalHitAccuracy"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.MAGICAL_ACCURACY);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Flyspeed"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.FLY_SPEED);
			return changes;
		}
		else if (stat.equalsIgnoreCase("speed"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.SPEED);
			return changes;
		}
		else if (stat.equalsIgnoreCase("PVPDefendRatio"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PVP_DEFEND_RATIO);
			return changes;
		}
		else if (stat.equalsIgnoreCase("PVPAttackRatio"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.PVP_ATTACK_RATIO);
			return changes;
		}
		else if (stat.equalsIgnoreCase("concentration"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.CONCENTRATION);
			return changes;
		}
		else if (stat.equalsIgnoreCase("PhysicalCriticalReduceRate"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.PHYSICAL_CRITICAL_RESIST);
			return changes;
		}
		else if (stat.equalsIgnoreCase("PhysicalCriticalDamageReduce"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.PHYSICAL_CRITICAL_DAMAGE_REDUCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MagicalCriticalReduceRate"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.MAGICAL_CRITICAL_RESIST);
			return changes;
		}
		else if (stat.equalsIgnoreCase("MagicalCriticalDamageReduce"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.MAGICAL_CRITICAL_DAMAGE_REDUCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("AllSpeed"))
		{
			StatFunc func = getFuncFor((String) function);
			if (skillId == 182)
				func = StatFunc.PERCENT;
			processChanges(changes, func, Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.SPEED, Modifiersenum.FLY_SPEED);
			return changes;
		}
		else if (stat.equalsIgnoreCase("BoostCastingTime"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? -1 : 1), Integer.parseInt((String) delta) * (isUp ? -1 : 1), Modifiersenum.BOOST_CASTING_TIME);
			return changes;
		}
		else if (stat.equalsIgnoreCase("magicalCritical"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.MAGICAL_CRITICAL);
			return changes;
		}
		else if (stat.equalsIgnoreCase("magicalAttack"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.MAGICAL_ATTACK);
			return changes;
		}
		else if (stat.equalsIgnoreCase("HealSkillBoost"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.BOOST_HEAL);
			return changes;
		}
		else if (stat.equalsIgnoreCase("ARAll") || stat.equalsIgnoreCase("allresist") || stat.equalsIgnoreCase("allpara"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1),
					Modifiersenum.ABNORMAL_RESISTANCE_ALL);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arRoot"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.ROOT_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arSnare"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.SNARE_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arStun"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STUN_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arsleep"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.SLEEP_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arSpin"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.SPIN_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arStumble"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STUMBLE_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arStagger"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STAGGER_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Stagger_Arp"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STAGGER_BOOST);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Stumble_Arp"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STUMBLE_BOOST);
			return changes;
		}
		else if (stat.equalsIgnoreCase("Stun_Arp"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STUN_BOOST);
			return changes;
		}
		else if (stat.equalsIgnoreCase("arStunlike"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.STUN_RESISTANCE,
					Modifiersenum.STUMBLE_RESISTANCE, Modifiersenum.STAGGER_RESISTANCE, Modifiersenum.SPIN_RESISTANCE, Modifiersenum.OPENAREIAL_RESISTANCE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("str"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.POWER);
			return changes;
		}
		else if (stat.equalsIgnoreCase("vit"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.HEALTH);
			return changes;
		}
		else if (stat.equalsIgnoreCase("agi"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.AGILITY);
			return changes;
		}
		else if (stat.equalsIgnoreCase("dex"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.ACCURACY);
			return changes;
		}
		else if (stat.equalsIgnoreCase("kno"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.KNOWLEDGE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("wil"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.WILL);
			return changes;
		}
		else if (stat.equalsIgnoreCase("knowil"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.WILL,
					Modifiersenum.KNOWLEDGE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("attackRange"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.ATTACK_RANGE);
			return changes;
		}
		else if (stat.equalsIgnoreCase("BoostSkillCost"))
		{
			processChanges(changes, getFuncFor((String) function), Integer.parseInt((String) value) * (isUp ? 1 : -1), Integer.parseInt((String) delta) * (isUp ? 1 : -1), Modifiersenum.BOOST_SKILL_COST);
			return changes;
		}
		else
			System.out.println("Missing stat: " + stat);
		return changes;
	}

	private static void processChanges(List<Change> changes, StatFunc func, int value, Object delta, Modifiersenum... mods)
	{
		for (Modifiersenum mod : mods)
		{
			Change change = new Change();
			change.setFunc(func);
			change.setValue(Integer.toString(value));
			change.setStat(mod);
			if (delta != null && (Integer)delta != 0)
				change.setDelta((Integer) delta);
			changes.add(change);
		}
	}
}
